package nio;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;

/**
 * Created by tony on 2017/7/12.
 */
public class Ping {
    // The default daytime port
    static int DAYTIME_PORT = 8013;

    // The port we'll actually use
    static int port = DAYTIME_PORT;

    // Representation of a ping target
    static class Target {
        InetSocketAddress address;
        SocketChannel channel;
        Exception failure;
        long connectStart;
        long connectFinish = 0;
        boolean shown = false;


        Target(String host) {
            try {
                address = new InetSocketAddress(InetAddress.getByName(host), port);
            } catch (IOException e) {
                failure = e;
            }
        }

        void show() {
            String result;
            if (connectFinish != 0) {
                result = Long.toString(connectFinish - connectStart) + "ms";
            } else if (failure != null) {
                result = failure.toString();
            } else {
                result = "Timed out";
            }
            System.out.println(address + " : " + result);
            shown = true;
        }
    }

    // Thread for printing targets as they're heard from
    static class Printer extends Thread {
        LinkedList pending = new LinkedList();
        Printer() {
            setName("Printer");
            super.setDaemon(true);
        }
        void add(Target t) {
            synchronized (pending) {
                pending.add(t);
                pending.notify();
            }
        }

        public void run() {
            try {
                for(;;) {
                    Target t = null;
                    synchronized (pending) {
                        while (pending.size() == 0) {
                            pending.wait();
                        }
                        t = (Target)pending.removeFirst();
                    }
                    t.show();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    // Thread for connecting to all targets in parallel via a single selector
    static class Connector extends Thread {
        Selector sel;
        Printer printer;

        // List of pending targets. We use this list because if we try to
        // register a channel with the selector while the connector thread is
        // blocked in the selector then we will block
        LinkedList pending = new LinkedList();
        Connector(Printer pr) throws IOException {
            printer = pr;
            sel = Selector.open();
            setName("Connector");
        }

        // Initiate a connection sequence to the given target and add the
        // target to the pending-target list
        void add(Target t) {
            SocketChannel sc = null;

        }
    }
}
